package com.minimalist.common.utils;

import com.minimalist.common.entity.lindi.po.LindiIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.geotools.data.*;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.*;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.*;

/**
 * 地理信息工具类
 *
 * @author 11987
 */
public class GeoUtil{

    private static final Logger log = LoggerFactory.getLogger(GeoUtil.class);

    /**
     * 读取SHP文件
     *
     * @param shpFilePath SHP文件路径
     * @return 要素集合
     */
    public static List<Map<String, Object>> readShpFile(String shpFilePath){
        return readShpFile(shpFilePath, "UTF-8");
    }

    /**
     * 读取SHP文件
     *
     * @param shpFilePath SHP文件路径
     * @param charset     字符集
     * @return 要素集合
     */
    public static List<Map<String, Object>> readShpFile(String shpFilePath, String charset){
        List<Map<String, Object>> resultList = new ArrayList<>();
        File file = new File(shpFilePath);

        try{
            // 创建数据存储
            Map<String, Object> map = new HashMap<>();
            map.put("url", file.toURI().toURL());
            DataStore dataStore = DataStoreFinder.getDataStore(map);

            // 设置字符集
            if (dataStore instanceof ShapefileDataStore){
                ((ShapefileDataStore) dataStore).setCharset(Charset.forName(charset));
            }

            // 获取要素类型名称
            String typeName = dataStore.getTypeNames()[0];

            // 获取要素源
            SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);

            // 获取要素集合
            SimpleFeatureCollection featureCollection = featureSource.getFeatures();

            // 遍历要素
            try (SimpleFeatureIterator features = featureCollection.features()){
                while (features.hasNext()){
                    SimpleFeature feature = features.next();
                    Map<String, Object> featureMap = new HashMap<>();

                    // 获取属性
                    Collection<Property> properties = feature.getProperties();
                    for (Property property : properties){
                        String name = property.getName().toString();
                        Object value = property.getValue();
                        featureMap.put(name, value);
                    }

                    // 获取几何信息
                    Geometry geometry = (Geometry) feature.getDefaultGeometry();
                    if (geometry != null){
                        featureMap.put("geometry", geometry);
                        featureMap.put("geometryType", geometry.getGeometryType());
                        featureMap.put("wkt", geometry.toText());
                    }

                    resultList.add(featureMap);
                }
            }

            // 关闭数据存储
            dataStore.dispose();

        } catch (IOException e){
            log.error("读取SHP文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("读取SHP文件失败", e);
        }

        return resultList;
    }

    /**
     * 获取SHP文件的属性结构
     *
     * @param shpFilePath SHP文件路径
     * @return 属性结构
     */
    public static Map<String, String> getShpFileSchema(String shpFilePath){
        Map<String, String> schema = new HashMap<>();
        File file = new File(shpFilePath);

        try{
            // 创建数据存储
            Map<String, Object> map = new HashMap<>();
            map.put("url", file.toURI().toURL());
            DataStore dataStore = DataStoreFinder.getDataStore(map);

            // 获取要素类型名称
            String typeName = dataStore.getTypeNames()[0];

            // 获取要素源
            FeatureSource<SimpleFeatureType, SimpleFeature> source = dataStore.getFeatureSource(typeName);

            // 获取要素类型
            SimpleFeatureType featureType = source.getSchema();

            // 获取属性名称和类型
            for (int i = 0; i < featureType.getAttributeCount(); i++){
                String name = featureType.getDescriptor(i).getLocalName();
                String type = featureType.getDescriptor(i).getType().getBinding().getSimpleName();
                schema.put(name, type);
            }

            // 关闭数据存储
            dataStore.dispose();

        } catch (IOException e){
            log.error("获取SHP文件属性结构失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取SHP文件属性结构失败", e);
        }

        return schema;
    }

    /**
     * 将SHP文件转换为GeoJSON
     *
     * @param shpFilePath SHP文件路径
     * @return GeoJSON字符串
     */
    public static String shpToGeoJson(String shpFilePath){
        StringBuilder geoJson = new StringBuilder();
        geoJson.append("{\"type\":\"FeatureCollection\",\"features\":[");

        List<Map<String, Object>> features = readShpFile(shpFilePath);
        for (int i = 0; i < features.size(); i++){
            Map<String, Object> feature = features.get(i);

            geoJson.append("{\"type\":\"Feature\",\"geometry\":");

            // 几何信息
            String wkt = (String) feature.get("wkt");
            if (wkt != null){
                // 简单处理WKT转GeoJSON，实际项目中可能需要更复杂的转换
                String geoType = (String) feature.get("geometryType");
                geoJson.append("{\"type\":\"").append(geoType).append("\",\"coordinates\":");

                // 这里简化处理，实际项目中需要根据几何类型进行更精确的转换
                String coordinates = wkt.substring(wkt.indexOf("("), wkt.lastIndexOf(")") + 1);
                coordinates = coordinates.replace(" ", ",");
                geoJson.append(coordinates).append("}");
            } else{
                geoJson.append("null");
            }

            // 属性信息
            geoJson.append(",\"properties\":{");
            boolean first = true;
            for (Map.Entry<String, Object> entry : feature.entrySet()){
                String key = entry.getKey();
                Object value = entry.getValue();

                // 跳过几何相关属性
                if ("geometry".equals(key) || "geometryType".equals(key) || "wkt".equals(key)){
                    continue;
                }

                if (!first){
                    geoJson.append(",");
                }
                first = false;

                geoJson.append("\"").append(key).append("\":");
                if (value == null){
                    geoJson.append("null");
                } else if (value instanceof Number){
                    geoJson.append(value);
                } else{
                    geoJson.append("\"").append(value).append("\"");
                }
            }
            geoJson.append("}}");

            if (i < features.size() - 1){
                geoJson.append(",");
            }
        }

        geoJson.append("]}");
        return geoJson.toString();
    }

    /**
     * 创建林地指标SHP文件
     *
     * @param outputPath 输出路径
     * @param indexList  林地指标列表
     * @return 是否创建成功
     */
    public static boolean createLindiIndexShapefile(String outputPath, List<LindiIndex> indexList){
        if (indexList == null || indexList.isEmpty()){
            log.error("林地指标列表为空，无法创建SHP文件");
            return false;
        }

        File outputFile = new File(outputPath);
        if (!outputFile.getParentFile().exists()){
            outputFile.getParentFile().mkdirs();
        }

        try{
            // 创建FeatureType
            SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
            builder.setName("LindiIndex");
            builder.setCRS(DefaultGeographicCRS.WGS84);

            // 添加几何字段
            builder.add("the_geom", Polygon.class);

            // 添加属性字段
            builder.add("indexId", Long.class);
            builder.add("location", String.class);
            builder.add("area", String.class);
            builder.add("north", String.class);
            builder.add("south", String.class);
            builder.add("east", String.class);
            builder.add("west", String.class);
            builder.add("status", Integer.class);

            SimpleFeatureType featureType = builder.buildFeatureType();

            // 创建Shapefile
            ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
            Map<String, Serializable> params = new HashMap<>();
            params.put("url", outputFile.toURI().toURL());
            params.put("create spatial index", Boolean.TRUE);

            ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
            dataStore.createSchema(featureType);
            dataStore.setCharset(Charset.forName("UTF-8"));

            // 获取FeatureWriter
            String typeName = dataStore.getTypeNames()[0];
            Transaction transaction = new DefaultTransaction("create");
            SimpleFeatureStore featureStore = (SimpleFeatureStore) dataStore.getFeatureSource(typeName);

            // 使用ListFeatureCollection替代FeatureCollections.newCollection()
            List<SimpleFeature> featureList = new ArrayList<>();
            // 创建几何工厂
            GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);

            // 为每个林地指标创建Feature
            for (LindiIndex index : indexList){
                // 创建一个简单的矩形多边形作为示例
                Polygon polygon = createPolygonFromBounds(geometryFactory, index);

                // 设置属性
                featureBuilder.add(polygon);
                featureBuilder.add(index.getIndexId());
                featureBuilder.add(index.getLocationName());

                SimpleFeature feature = featureBuilder.buildFeature(null);
                featureList.add(feature);
            }

            SimpleFeatureCollection collection = new ListFeatureCollection(featureType, featureList);
            featureStore.setTransaction(transaction);
            try{
                featureStore.addFeatures(collection);
                transaction.commit();
            } catch (Exception e){
                log.error("添加要素失败: {}", e.getMessage(), e);
                transaction.rollback();
                return false;
            } finally{
                transaction.close();
            }

            dataStore.dispose();
            return true;
        } catch (Exception e){
            log.error("创建林地指标SHP文件失败: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 根据四至信息创建多边形
     *
     * @param geometryFactory 几何工厂
     * @param index           林地指标
     * @return 多边形
     */
    private static Polygon createPolygonFromBounds(GeometryFactory geometryFactory, LindiIndex index){
        // 这里简化处理，假设四至信息是经纬度坐标
        // 实际应用中，需要根据实际的四至信息格式进行解析

        // 创建矩形多边形的坐标
        Coordinate[] coords = new Coordinate[5];

        LinearRing ring = geometryFactory.createLinearRing(coords);
        return geometryFactory.createPolygon(ring, null);
    }

    /**
     * 解析坐标字符串为double值
     *
     * @param coordinate 坐标字符串
     * @return 坐标double值
     */
    private static double parseCoordinate(String coordinate){
        try{
            // 尝试直接解析为double
            return Double.parseDouble(coordinate);
        } catch (NumberFormatException e){
            // 如果解析失败，可能是度分秒格式，需要进行转换
            // 这里简化处理，返回默认值
            log.warn("无法解析坐标: {}", coordinate);
            return 0.0;
        }
    }

    /**
     * 生成林地指标SHP文件示例
     *
     * @param outputPath 输出路径
     * @return 是否生成成功
     */
    public static boolean generateLindiIndexShapefileExample(String outputPath){
        // 创建示例林地指标数据
        List<LindiIndex> indexList = new ArrayList<>();

        // 示例1：东莞市长安镇
        LindiIndex index1 = LindiIndex.builder()
                .indexId(UnqIdUtil.uniqueId())
                .locationName("长安镇")
                .build();

        // 示例2：东莞市虎门镇
        LindiIndex index2 = LindiIndex.builder()
                .indexId(UnqIdUtil.uniqueId())
                .locationName("虎门镇")
                .build();

        // 示例3：东莞市大朗镇
        LindiIndex index3 = LindiIndex.builder()
                .indexId(UnqIdUtil.uniqueId())
                .locationName("大朗镇")
                .build();

        indexList.add(index1);
        indexList.add(index2);
        indexList.add(index3);

        // 创建SHP文件
        return createLindiIndexShapefile(outputPath, indexList);
    }

    public static void main(String[] args){
        // 生成林地指标SHP文件示例
        String outputPath = "D:/data/lindi_index.shp";
        boolean success = GeoUtil.generateLindiIndexShapefileExample(outputPath);
        if (success){
            System.out.println("林地指标SHP文件生成成功：" + outputPath);
        } else{
            System.out.println("林地指标SHP文件生成失败");
        }

// 读取生成的SHP文件
        List<Map<String, Object>> features = GeoUtil.readShpFile(outputPath);
        System.out.println("读取到的林地指标数据：");
        for (Map<String, Object> feature : features){
            System.out.println("镇街名称：" + feature.get("location"));
            System.out.println("林地面积：" + feature.get("area"));
            System.out.println("北界：" + feature.get("north"));
            System.out.println("南界：" + feature.get("south"));
            System.out.println("东界：" + feature.get("east"));
            System.out.println("西界：" + feature.get("west"));
            System.out.println("几何类型：" + feature.get("geometryType"));
            System.out.println("----------------------------");
        }
    }
}
